/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package genotypes;

import java.util.Arrays;
import objectives.ObjectiveFunction;

/**
 *
 * @author rusak
 */
public class AnglesPopulation {

    private Angles population[];
    private int size;
    private int unaccCount, accCount;

    public AnglesPopulation(Angles[] population) {
        this.population = population;
        size = population.length;
    }

    public static AnglesPopulation randomPopulation(int size, int popSize, double limitations[][]) {
        Angles result[] = new Angles[popSize];
        for (int i = 0; i < popSize; i++) {
            result[i] = Angles.randomAngles(size, limitations);
        }
        return new AnglesPopulation(result);
    }

    public Angles[] getAcceptable() {
        Angles result[] = new Angles[accCount];
        int w = 0;
        for (int i = 0; i < size; i++) {
            if (population[i].isAcceptable()) {
                result[w] = population[i].copy();

                w++;
            }
        }
        return result;
    }

    public Angles[] getUnacceptable() {
        Angles result[] = new Angles[unaccCount];
        int w = 0;
        for (int i = 0; i < size; i++) {
            if (!population[i].isAcceptable()) {
                result[w] = population[i].copy();
                w++;
            }
        }
        return result;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public Angles getAnglesAt(int i) {
        return population[i];
    }
    
    public Angles[] getPopulation() {
        return population;
    }

    public static AnglesPopulation merge(Angles[] anglesTable1, Angles[] anglesTable2) {
        int size = anglesTable1.length + anglesTable2.length;

        int sec = anglesTable1.length;
        Angles result[] = Arrays.copyOf(anglesTable1, size);
        for (int i = sec; i < size; i++) {
            result[i] = anglesTable2[i - sec];
        }

        return new AnglesPopulation(result);
    }

    public void refreshAcceptability() {
        unaccCount = 0;
        accCount = 0;
        for (int i = 0; i < size; i++) {

            if (population[i].isAcceptable()) {
                accCount++;
            } else {
                unaccCount++;
            }
        }
    }

    public void evaluate(ObjectiveFunction f) {
        unaccCount = 0;
        accCount = 0;
        for (int i = 0; i < size; i++) {
            population[i].setEvaluation(f.evaluate(population[i]));
            if (population[i].isAcceptable()) {
                accCount++;
            } else {
                unaccCount++;
            }
        }
    }

    public Angles bestIndividual() {
        int j = 0;
        while(!population[j].isAcceptable()) {
            if(j>=population.length-1) {System.out.println("ASDASDASDASDASDASDASD"); return null;}
            j++;
        }
        Angles best = population[j];
        double bestEval = population[j].getDistanceToDest();
        double res;
        for (int i = j+1; i < size; i++) {
            if (population[i].isAcceptable()
                    && (res = population[i].getDistanceToDest()) < bestEval) {
                best = population[i];
                bestEval = res;
            }
        }
        return best.copy();
    }

    private Angles[] copy() {
        Angles copied[] = new Angles[population.length];
        for (int i = 0; i < population.length; i++) {
            copied[i] = population[i].copy();
        }

        return copied;
    }

    public AnglesPopulation copyOf() {
        return new AnglesPopulation(copy());
    }

    public Angles[] bestIndividuals(int howMuch) {
        if (howMuch >= population.length) {
            return copy();
        }

        Arrays.sort(population, new AnglesComparator());
        Angles result[] = new Angles[howMuch];
        for (int i = 0; i < howMuch; i++) {
            result[i] = population[i].copy();
        }
        return result;
    }

    @Override
    public String toString() {
        StringBuilder s = new StringBuilder();
        s.append("ANGLES POPULATION: \n");
        for (int i = 0; i < size; i++) {
            s.append(population[i]);
            s.append("   eval: ");
            s.append(population[i].getDistanceToDest());
            s.append("   acc: ");
            s.append(population[i].isAcceptable());
            s.append("\n");
        }
        return s.toString();
    }
}
